package com.example.demo.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Result;
import com.example.demo.entity.ScRecord;
import com.example.demo.entity.ScShift;
import com.example.demo.entity.ScSource;
import com.example.demo.entity.SysUser;
import com.example.demo.entity.excel.CheckExportEntity;
import com.example.demo.entity.excel.CheckinEntity;
import com.example.demo.mapper.ScRecordMapper;
import com.example.demo.mapper.ScShiftMapper;
import com.example.demo.mapper.ScSourceMapper;
import com.example.demo.service.impl.ScRecordServiceImpl;
import com.example.demo.service.impl.ScSourceServiceImpl;
import com.example.demo.utils.DateTransferUtil;
import com.example.demo.utils.TokenUtils;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@RequestMapping("/checkin")
public class ScRecordController {
    @Autowired
    ScRecordServiceImpl scRecordService;
    @Autowired
    ScSourceServiceImpl scSourceService;
    @Resource
    ScRecordMapper scRecordMapper;
    @Resource
    ScShiftMapper scShiftMapper;
    @Resource
    ScSourceMapper scSourceMapper;

    private static SimpleDateFormat format1 = new SimpleDateFormat("yyyy/M/d H:m:s");
    private static SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd");
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static SimpleDateFormat dateFormat1 = new SimpleDateFormat("HH:mm");
    private static SimpleDateFormat dateFormat3 = new SimpleDateFormat("yyyy-MM");

    @PostMapping("/update")
    public Result<?> update(@RequestBody List<ScRecord> scRecords, HttpServletRequest request) throws ParseException {
        SysUser sysUser = TokenUtils.getUserInfo(request);
        if (sysUser == null)
            return Result.error("500", "未获取到user信息");
        for (ScRecord scRecord : scRecords){
            scRecord.setModifyUser(sysUser.getPeopleName());
            scRecord.setModifyTime(dateFormat.format(new Date()));

            BigDecimal bd = new BigDecimal(0);
            BigDecimal bd1 = new BigDecimal(0);
            if (StrUtil.isNotEmpty(scRecord.getMin()) && StrUtil.isNotEmpty(scRecord.getMax())){
                if (scRecord.getMin().equals(scRecord.getMax())) {
                    return Result.error("401", "上下班打卡时间相同");
                }
                scRecord.setLack(0);
                bd = scRecordService.calculate1(scRecord.getMin(), scRecord.getMax());
            }
            if (StrUtil.isNotEmpty(scRecord.getMin1()) && StrUtil.isNotEmpty(scRecord.getMax1())){
                if (scRecord.getMin1().equals(scRecord.getMax1())) {
                    return Result.error("401", "上下班打卡时间相同");
                }
                scRecord.setLack(0);
                bd1 = scRecordService.calculate1(scRecord.getMin1(), scRecord.getMax1());
            }
            scRecord.setWorkTime(bd.add(bd1));
            scRecordMapper.updateById(scRecord);
        }
        return Result.success();
    }

    @PostMapping("/test")
    public Result<?> test(@RequestParam String test) {
        ScRecord scRecord = new ScRecord();
        scRecord.setName(test);
        if (test.equals("△")) {
            return null;
        }
        return Result.success(scRecordMapper.insert(scRecord));
    }

    @GetMapping("/list")
    public synchronized Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,
                                           @RequestParam(defaultValue = "10") Integer pageSize,
                                           @RequestParam(defaultValue = "") String lack,
                                           @RequestParam(defaultValue = "") String type,
                                           @RequestParam(defaultValue = "") String date,
                                           @RequestParam(defaultValue = "") String date1,
                                           @RequestParam(defaultValue = "") String name) {
        LambdaQueryWrapper<ScRecord> wrapper = Wrappers.lambdaQuery();
        if (StrUtil.isNotBlank(name)) {
            wrapper.like(ScRecord::getName, name);
        }
        if (StrUtil.isNotBlank(type)) {
            wrapper.like(ScRecord::getAttendanceType, type);
        }
        if (StrUtil.isNotEmpty(date)) {
            List<String> list = scRecordService.getDate(date);
            if (list == null) return Result.error("401", "月份格式错误");
            wrapper.ge(ScRecord::getDate, list.get(0));
            wrapper.le(ScRecord::getDate, list.get(1));
        }
        if (StrUtil.isNotEmpty(date1)) {
            wrapper.eq(ScRecord::getDate, date1);
        }
        if (!StrUtil.isBlank(lack)){
            if(lack.equals("0")){
                wrapper.eq(ScRecord::getLack, 0);
            }
            if(lack.equals("1")){
                wrapper.eq(ScRecord::getLack, 1);
            }
        }
        Page<ScRecord> scRecordPage = scRecordMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
        return Result.success(scRecordPage);
    }

    @PostMapping("/list1")
    public Result<?> unionList(@RequestParam(defaultValue = "1") int pageNum,
                               @RequestParam(defaultValue = "10") int pageSize,
                               @RequestParam(defaultValue = "") String name,
                               @RequestParam(defaultValue = "") String department,
                               @RequestParam String date){
        try {
            Date date1 = dateFormat3.parse(date);
        } catch (ParseException e) {
            return Result.error("401", "日期格式错误");
        }
        String date1 = DateTransferUtil.getFirstDay(date);
        String date2 = DateTransferUtil.getLastDay(date);
        Page<CheckExportEntity> scRecordPage = new Page<>();
        scRecordPage.setSize(pageSize);
        scRecordPage.setCurrent(pageNum);

        Map<String, Object> map = scRecordService.export1(date1, date2, department);
        List<CheckExportEntity> list = (List<CheckExportEntity>) map.get("list");
        scRecordPage.setTotal(list.size());
        int right = (int) map.get("right");
        int wrong = (int) map.get("wrong");

        List<CheckExportEntity> list1 = new ArrayList<>();
        List<CheckExportEntity> result;
        if (StrUtil.isNotBlank(name)){
            for (CheckExportEntity item : list){
                if (item.getName().equals(name))
                    list1.add(item);
            }
            result = scRecordService.page(list1, pageSize, pageNum);
        } else {
            result = scRecordService.page(list, pageSize, pageNum);
        }
        scRecordPage.setRecords(result);
        scRecordPage.setMaxLimit((long) right);
        scRecordPage.setCountId(String.valueOf(wrong));

        return Result.success(scRecordPage);
    }

    @GetMapping("/rank")
    public Result<?> getRank(@RequestParam String date, @RequestParam String department){
        try {
            Date date1 = dateFormat3.parse(date);
        } catch (ParseException e) {
            return Result.error("401", "日期格式错误");
        }
        String date1 = DateTransferUtil.getFirstDay(date);
        String date2 = DateTransferUtil.getLastDay(date);
        return Result.success(scRecordService.getRank(date1, date2, department));
    }

    @GetMapping("/list2")
    public synchronized Result<?> getInfo(@RequestParam(defaultValue = "") List<String> ids) {
        List<ScRecord> list = new ArrayList<>();
        for (String item : ids){
            ScRecord scRecord = scRecordMapper.selectById(item);
            if (scRecord == null) return Result.error("402", "找不到id=" + item + "的scRecord对象");
            list.add(scRecord);
        }
        return Result.success(list);
    }

    @GetMapping("/{id}")
    public synchronized Result<?> get(@PathVariable Long id) {
        return Result.success(scRecordMapper.selectById(id));
    }

    @GetMapping("/name")
    public Result<?> getName(@RequestParam(defaultValue = "") String date,
                             @RequestParam(defaultValue = "") String department) {
        if (StrUtil.isEmpty(department)) return Result.error("401", "缺少部门名称");
        if (StrUtil.isEmpty(date)) {
            return Result.success(scRecordMapper.getNameList1(department));
        } else {
            try{
                Date date1 = dateFormat1.parse(date);
            } catch (ParseException e){
                return Result.error("401", "月份格式错误");
            }
            String date1 = DateTransferUtil.getFirstDay(date);
            String date2 = DateTransferUtil.getLastDay(date);
            return Result.success(scRecordMapper.getNameList2(date1, date2, department));
        }
    }

    @ApiOperation(value = "导出excel表格", notes = "导出加班和工作时长表")
    @GetMapping("/export1/{date}/{department}")
    public void exportInfo1(@PathVariable String date,
                            @PathVariable String department,
                            HttpServletResponse response) {
        String date1 = DateTransferUtil.getFirstDay(date);
        String date2 = DateTransferUtil.getLastDay(date);
        Map<String, Object> excelMap = scRecordService.export1(date1, date2, department);
        excelMap.put("date", date);

        TemplateExportParams params = new TemplateExportParams("static/sc/checkin_template.xlsx", true);
        Workbook workBook = null;
        try {
            workBook = ExcelExportUtil.exportExcel(params, excelMap);
            response.setHeader("content-Type", "application/octet-stream");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode("月度物业人员考勤汇总.xlsx", "UTF-8"));
            workBook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("导出异常");
        }finally {
            if (workBook != null) {
                try {
                    workBook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @ApiOperation(value = "导入考勤数据")
    @PostMapping("/import1")
    public Result<?> importExcel(MultipartFile file, HttpServletRequest request) throws Exception {
        SysUser sysUser = TokenUtils.getUserInfo(request);
        if (sysUser == null)
            return Result.error("500", "未获取到user信息");

        //读文件，处理源数据，存进source
        List<ScSource> scSources = CollUtil.newArrayList();
        ImportParams params = new ImportParams();
        params.setHeadRows(1);
        InputStream inputStream = file.getInputStream();
        List<CheckinEntity> records = ExcelImportUtil.importExcel(inputStream, CheckinEntity.class, params);

        try{
            for (CheckinEntity item : records){
                if (StrUtil.isBlank(item.getName()) && StrUtil.isBlank(item.getDepartment()) && StrUtil.isBlank(item.getDate()))
                    continue;
                ScSource scSource = new ScSource();
                scSource.setName(item.getName());

                if (item.getDepartment().equals("职能"))
                    scSource.setDepartment("管理");
                else
                    scSource.setDepartment(item.getDepartment());

                Date date = format1.parse(item.getDate());
                scSource.setTime(dateFormat1.format(date));
                scSource.setDay(format2.format(date));

                LambdaQueryWrapper<ScShift> wrapper = Wrappers.lambdaQuery();
                wrapper.eq(ScShift::getName, scSource.getName()).eq(ScShift::getMonth, scSource.getDay().substring(0, 7));
                List<ScShift> scShifts = scShiftMapper.selectList(wrapper);
                if (scShifts.size() == 0) {
                    return Result.error("401", "找不到" + scSource.getName() + "的排班表");
                }
                scSources.add(scSource);
            }
        }catch (Exception e){
            return Result.error("401", "有点问题");
        }
        if (!scSourceService.saveBatch(scSources))
            return Result.error("5001", "存scSource有点问题");

        //处理source，存进record
        String time = scSources.get(0).getDay();
        List<Map<String, Object>> list = scSourceMapper.data(DateTransferUtil.getMinMonthDate(time), DateTransferUtil.getMaxMonthDate(time));
        List<ScRecord> scRecords = new ArrayList<>();
        for (Map<String, Object> item : list){
            ScRecord scRecord = new ScRecord();
            scRecord.setName((String) item.get("name"));
            scRecord.setAttendanceType((String) item.get("department"));
            scRecord.setMax((String) item.get("max"));
            scRecord.setMin((String) item.get("min"));
            if (scRecord.getMin().equals(scRecord.getMax())) scRecord.setMax("");
            scRecord.setDate((String) item.get("day"));
            scRecord.setCreateUser(sysUser.getPeopleName());
            scRecord.setCreateTime(dateFormat.format(new Date()));

            //获取此人此日期的排班方式
            LambdaQueryWrapper<ScShift> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(ScShift::getName, scRecord.getName()).eq(ScShift::getMonth, scRecord.getDate().substring(0, 7));
            List<ScShift> scShifts = scShiftMapper.selectList(wrapper);
            ScShift scShift = scShifts.get(0);

            String d = scRecord.getDate().substring(8);
            StringBuilder sb = new StringBuilder(d);
            sb.insert(0, "day");

            String shift = null;
            Field[] fields = scShift.getClass().getDeclaredFields();
            for (Field field : fields) {
                //设置允许通过反射访问私有变量
                field.setAccessible(true);
                //获取字段的名称
                String name = field.getName();
                if (name.contentEquals(sb)) {
                    shift = field.get(scShift).toString();
                    break;
                }
            }
            //判断是否异常：休息日有打卡记录、非休息日缺打卡记录
            if (StrUtil.isEmpty(shift)) return Result.error("401", "shift有点问题");
            if (shift.equals("⚪")) {
                if (StrUtil.isNotEmpty(scRecord.getMin()) || StrUtil.isNotEmpty(scRecord.getMax()))
                    scRecord.setLack(1);
            } else {
                if (StrUtil.isEmpty(scRecord.getMin()) || StrUtil.isEmpty(scRecord.getMax())) {
                    scRecord.setLack(1);
                } else {
                    //如果两次打卡之间小于5分钟也置异常
                    if (scRecordService.calculate1(scRecord.getMin(), scRecord.getMax()).compareTo(new BigDecimal(5)) <= 0)
                        scRecord.setLack(1);
                    //计算上下班时间
                    if (shift.equals("∆")) {
                        BigDecimal bd1, bd2;
                        bd1 = scRecordService.calculate1("00:00", scRecord.getMin());
                        bd2 = scRecordService.calculate1(scRecord.getMax(), "23:59").add(new BigDecimal(1));
                        scRecord.setWorkTime(bd1.add(bd2));
                    } else {
                        BigDecimal bd;
                        bd = scRecordService.calculate1(scRecord.getMin(), scRecord.getMax());
                        scRecord.setWorkTime(bd);
                    }
                    scRecord.setLack(0);
                }
            }
            if (scRecord.getLack() == 1) scRecord.setWorkTime(new BigDecimal(0));
            scRecords.add(scRecord);
        }
        if (!scRecordService.saveBatch(scRecords)) return Result.error("403", "scResource转scRecord有点问题");

        return Result.success();
    }
}
